/*
 * AliveChecker.h
 *
 *  Created on: 2013. 10. 7.
 *      Author: jjaehuny
 */

#ifndef PROJECTZ_GLOBALCHECKER_H_
#define PROJECTZ_GLOBALCHECKER_H_

#include <Dispatcher/Timer.h>

#include "Proxy.h"
#include "User.h"

#include "NLogic/Function.h"
#include "NLogic/Score.h"
#include "NResource/Static.h"

#include <algorithm>

#include <ctime>

#include "Config.h"

namespace ProjectZ {

class GlobalChecker : public::Dispatcher::Timer::IObserver
{
public:
	enum class TimerID {
		__NOLE__,
		ALIVE_USER,
		SWAP_WIN_POINT,
		SERVER_ADDR_CCU,

		CHECK_PACKET_POOL,

		CHECK_PACKET_PROCESS_COUNT,

		WORLD_BOSS_RANK,
		__MAX__,
	};
public:
	GlobalChecker() {
		::Dispatcher::Timer::Argument clsArgument(1000 * 60 * 10, static_cast<int>(TimerID::ALIVE_USER), NULL, this);
		::Dispatcher::GETTIMER()->SetTimer(clsArgument);

		::Dispatcher::Timer::Argument clsSvrAddrArg(1000, static_cast<int>(TimerID::SERVER_ADDR_CCU), NULL, this);
		::Dispatcher::GETTIMER()->SetTimer(clsSvrAddrArg);

		time_t curTime = time(NULL);
		time_t nextInitTime = NLogic::NFunction::GetNextWeekInitTime();

		DEBUGLOG("nextInitTime=%d, curTime=%d, gap=%d", nextInitTime, curTime, nextInitTime - curTime);
		::Dispatcher::Timer::Argument clsSwapWinPoint(1000 * (nextInitTime - curTime), static_cast<int>(TimerID::SWAP_WIN_POINT), NULL, this);
		::Dispatcher::GETTIMER()->SetTimer(clsSwapWinPoint);


		::Dispatcher::Timer::Argument clsPacketPool(1000 * 60 * 10, static_cast<int>(TimerID::CHECK_PACKET_POOL), NULL, this);
		::Dispatcher::GETTIMER()->SetTimer(clsPacketPool);

		::Dispatcher::Timer::Argument clsPacketCount(1000, static_cast<int>(TimerID::CHECK_PACKET_PROCESS_COUNT), NULL, this);
		::Dispatcher::GETTIMER()->SetTimer(clsPacketCount);

	}
	~GlobalChecker() {

	}

	bool OnTime(int id, void* param)
	{
		switch(id)
		{
		case static_cast<int>(TimerID::ALIVE_USER):
			{

				typedef std::map<int, User *> USERTREE;
				const USERTREE & clsUserTree = ::ProjectZ::NProxy::GetUserTree();
				std::vector<User *> clsVector;

				std::for_each(clsUserTree.begin(), clsUserTree.end(), [&](const USERTREE::value_type & pair) {
					if (pair.second->GetLastLatency() + ( 1000 * 60 * 10 ) < ProjectZ::NLogic::NFunction::GetTickCount())
					{
						clsVector.push_back(pair.second);
						//pair.second->CleanUp();
					}
				} );

				std::for_each(clsVector.begin(), clsVector.end(), [&](User * pUser) {
					//pUser->CleanUp();
					User::State * pState = pUser->GetState();
					if (NULL != pState)
						pState->OnClose(pUser, true);
				} );
				clsVector.clear();

//				::Logger::GETLOG()->ToAll(::Logger::OBSERVER, "NETWORK READ_NEW : %d SEND_NEW : %d", ::Network::GETPACKETPOOL()->GET_READ_ALLOC_COUNT()
//						, ::Network::GETPACKETPOOL()->GET_SEND_ALLOC_COUNT());
			}

			// 10 분당 한번 이므로 여기서 World_Boss_Rank 를 조회 한다.....

			NLogic::Static::Instance().GETWORLDBOSSRANK()->LoadWorldBossRank();

			break;
		case static_cast<int>(TimerID::SERVER_ADDR_CCU):
			{
				::ProjectZ::NLogic::ServerAddrCCU * clsSvrAddr = ::ProjectZ::NLogic::Static::Instance().GETSERVERADDRCCU();

				clsSvrAddr->SetServerAddr();

				if(false == ::ProjectZ::Config::Instance().GetResourceDatabase()._isBlock)
					break;

				std::vector<User *> kickUserVector;
				auto & clsUserTree = ::ProjectZ::NProxy::GetUserTree();
				if(10 < clsUserTree.size())
				{
					auto iter = clsUserTree.begin();
					int nCount = 0;
					while(true)
					{
						if (iter == clsUserTree.end())
							break;

						User * pUser = iter->second;
						if( true == NResource::Static::Instance().GetAllowUserResource()->IsAllowUser(pUser->GetSocialID().c_str()) )
						{
							++iter;
							continue;
						}

						if (pUser->GetState() == NState::Static::Instance().WAITRECONNECT() ||
							pUser->GetState() == NState::Static::Instance().CLEANUP())
						{
							++iter;
							continue;
						}

						++iter;
						++nCount;

						kickUserVector.push_back(pUser);

						if (nCount >= 10)
							break;
					}

//					for(int i = 0; i < 10; i++, ++iter)
//					{
//						User * pUser = iter->second;
//
//						if( true == NResource::Static::Instance().GetAllowUserResource()->IsAllowUser(pUser->GetSocialID().c_str()) )
//							continue;
//
//						kickUserVector.push_back(pUser);
//					}
				}
				else
				{
					auto iter = clsUserTree.begin();
					for(; iter != clsUserTree.end(); ++iter)
					{
						User * pUser = iter->second;

						if( true == NResource::Static::Instance().GetAllowUserResource()->IsAllowUser(pUser->GetSocialID().c_str()) )
							continue;

						if (pUser->GetState() == NState::Static::Instance().WAITRECONNECT() ||
							pUser->GetState() == NState::Static::Instance().CLEANUP())
						{
							continue;
						}

						kickUserVector.push_back(pUser);
					}
				}

				std::for_each(kickUserVector.begin(), kickUserVector.end(), [&](std::vector<User *>::value_type & pair){
					if( 0 != pair->GetSocialID().compare("0000000000") && NULL != pair )
					{
						User::State * pState = pair->GetState();
						if (NULL != pState)
							pState->OnClose(pair, true);
					}
				});
			}
			break;

		case static_cast<int>(TimerID::SWAP_WIN_POINT):
			{
				DEBUGLOG("Boooom!!!! Swap Point Timer!");

				// 로그인 한 유저들을 대상으로 승점 데이터 변경
				typedef std::map<int, User *> USERTREE;
				const USERTREE & clsUserTree = ProjectZ::NProxy::GetUserTree();

				std::for_each(clsUserTree.begin(), clsUserTree.end(), [&](const USERTREE::value_type & pair) {
//					DEBUGLOG("BEFORE UserSeq=%d, CurPoint=%d, LastPoint=%d", pair.second->GetUserSeq(), pair.second->GetUserInfo().wp_cur_week, pair.second->GetUserInfo().wp_last_week);
					pair.second->GetUserInfo().wp_last_week		= pair.second->GetUserInfo().wp_cur_week;
					pair.second->GetUserInfo().wp_last_reg_date = pair.second->GetUserInfo().wp_reg_date;
					pair.second->GetUserInfo().wp_cur_week		= 0;
					pair.second->GetUserInfo().wp_reg_date		= NLogic::NFunction::GetWeekInitTime();
					pair.second->GetUserInfo().score			= 0;
					pair.second->GetUserInfo().heart_blocked	= 0;

					// 승점 정보 Memcache에 반영
					pair.second->GetScore()->SetMemcache();
//					DEBUGLOG("AFTER  UserSeq=%d, CurPoint=%d, LastPoint=%d", pair.second->GetUserSeq(), pair.second->GetUserInfo().wp_cur_week, pair.second->GetUserInfo().wp_last_week);
				} );
				// 타이머 재설정
				::Dispatcher::GETTIMER()->KillTimer(this, static_cast<int>(TimerID::SWAP_WIN_POINT));

				if (true == ::ProjectZ::Config::Instance().GetResourceDatabase()._isTest)
				{
					int rankCycle = ::ProjectZ::Config::Instance().GetResourceFile()._rankCycle;

					::Dispatcher::Timer::Argument clsSwapWinPoint(1000 * rankCycle, static_cast<int>(TimerID::SWAP_WIN_POINT), NULL, this);
					::Dispatcher::GETTIMER()->SetTimer(clsSwapWinPoint);
				}
				else
				{
					::Dispatcher::Timer::Argument clsSwapWinPoint(1000 * 60 * 60 * 24 * 7, static_cast<int>(TimerID::SWAP_WIN_POINT), NULL, this);
					::Dispatcher::GETTIMER()->SetTimer(clsSwapWinPoint);
				}
			}
			break;
		case static_cast<int>(TimerID::CHECK_PACKET_POOL):
			{
				::Logger::GETLOG()->ToAll(::Logger::OBSERVER, "NETWORK READ_INIT : %d READ_ALLOC : %d READ_NEW : %d READ_DEL : %d SEND_INIT : %d SEND_ALLOC : %d SEND_NEW : %d SEND_DEL : %d",
						::Network::GETPACKETPOOL()->Get_init_read_count(),
						::Network::GETPACKETPOOL()->Get_read_alloc_count(),
						::Network::GETPACKETPOOL()->Get_READ_NEW_COUNT(),
						::Network::GETPACKETPOOL()->Get_READ_DEL_COUNT(),
						::Network::GETPACKETPOOL()->Get_init_send_count(),
						::Network::GETPACKETPOOL()->Get_send_alloc_count(),
						::Network::GETPACKETPOOL()->Get_SEND_NEW_COUNT() - 1024,
						::Network::GETPACKETPOOL()->Get_SEND_DEL_COUNT());
			}
			break;
		case static_cast<int>(TimerID::CHECK_PACKET_PROCESS_COUNT):
			{
			}
			break;
		default:
			break;
		}

		return true;
	}
};

} /*ProjectZ*/

#endif /* PROJECTZ_GLOBALCHECKER_H_ */
